plotly

This provides an overview to using plotly as the plotting engine with fivecentplots

Setup

Import packages


%load_ext autoreload
%autoreload 2
import fivecentplots as fcp
import pandas as pd
import imageio.v3 as imageio
import cv2
from pathlib import Path
fcp.__version__
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

'0.6.0-a2'

Sample data

Several data sets are used in this tutorial:

x-y data


df_xy = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data.csv')
df_xy.head(10)

Substrate Target Wavelength Boost Level Temperature [C] Die Voltage I Set I [A]
0 Si 450 0.2 25 (1,1) 0.0 0.0 0.0
1 Si 450 0.2 25 (1,1) 0.1 0.0 0.0
2 Si 450 0.2 25 (1,1) 0.2 0.0 0.0
3 Si 450 0.2 25 (1,1) 0.3 0.0 0.0
4 Si 450 0.2 25 (1,1) 0.4 0.0 0.0
5 Si 450 0.2 25 (1,1) 0.5 0.0 0.0
6 Si 450 0.2 25 (1,1) 0.6 0.0 0.0
7 Si 450 0.2 25 (1,1) 0.7 0.0 0.0
8 Si 450 0.2 25 (1,1) 0.8 0.0 0.0
9 Si 450 0.2 25 (1,1) 0.9 0.0 0.0

Time series data


ts = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_ts.csv')
ts.head()

Date Happiness Quotient
0 1/1/2015 16.088954
1 1/2/2015 18.186724
2 1/3/2015 35.744313
3 1/4/2015 38.134045
4 1/5/2015 46.147279

Bar plot data


df_bar = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_bar.csv')
df_bar.head()

Liquid pH Measurement T [C]
0 Lemon juice 2.4 A 25
1 Orange juice 3.5 A 25
2 Battery acid 1.0 A 25
3 Bottled water 6.7 A 25
4 Coke 3.0 A 25

Box plot data


df_box = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_box.csv')
df_box.head()

Batch Sample Region Value ID
0 101 1 Alpha123 3.5 ID701223A
1 101 1 Alpha123 0.0 ID7700-1222B
2 101 1 Alpha123 3.3 ID701223A
3 101 1 Alpha123 3.2 ID7700-1222B
4 101 1 Alpha123 4.0 ID701223A

Contour data


df_contour = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_contour.csv')
df_contour.head()

Experiment Batch X Y Value
0 Control 101 1 -4 3.5
1 Control 101 1 -2 2.1
2 Control 101 1 0 3.3
3 Control 101 1 2 3.2
4 Control 101 1 4 4.0

Gantt data


df_gantt = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_gantt.csv')
df_gantt.head()

Task Assigned Start Stop Category
0 Record drums Taylor 2010-09-01 2010-09-05 Recording
1 Record bass Nate 2010-09-04 2010-09-06 Recording
2 Record rhythm guitar Pat 2010-09-06 2010-09-08 Recording
3 Record rhythm guitar Dave 2010-09-06 2010-09-08 Recording
4 Record lead guitar Chris 2010-09-07 2010-09-09 Recording

Heatmap data


df_heatmap = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_heatmap.csv')
df_heatmap.head()

Player Category Average
0 Lebron James Points 27.5
1 Lebron James Assists 9.1
2 Lebron James Rebounds 8.6
3 Lebron James Blocks 0.9
4 James Harden Points 30.4

Histogram data


df_hist = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_box.csv')
img_hist = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))

Image data


img_bgr = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

Theme and shortcuts

Load a custom theme file for plotly:


fcp.set_theme('gray_plotly')
Previous theme file found! Renaming to "defaults_old.py" and copying theme "gray_plotly"...done!

Note

While many theme parameters can be common between matplotlib and plotly, certain differences between the engines (such as the default dpi) make it easier to use a custom theme file for each engine

Define some scope-wide shortcuts to avoid having to enter certain kwargs into each function call (i.e., these are automatically added):


fcp.KWARGS['inline'] = True
fcp.KWARGS['engine'] = 'plotly'

Caution

Not all features available in matplotlib are available in plotly. fivecentplots will attempt to warn you if you are requesting an unsupported feature, but not every possible option has been tested. Buyer beware (and then file a bug report!)

plot

Scatter

No legend


fcp.plot(df_xy, x='Voltage', y='I [A]', lines=False, ax_size=[400, 400])

Filtered


fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False,
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')

Legend


fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die',
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')

Log axis

Note

symlog and logit not yet supported


fcp.plot(df_xy, x='Voltage', y='I [A]', ax_scale='loglog', legend='Die', xmin=0.9, xmax=2.1, grid_minor=True,
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')

Categorical tick labels


fcp.plot(df_xy, x='Die', y='I [A]',
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25 & Voltage==1.5')

Time series


fcp.plot(ts, x='Date', y='Happiness Quotient', markers=False, ax_size=[1000, 250])

Secondary axes

Note

Not all secondary and multiple axes cases are shown below but all the matplotlib examples in plot have been ported


fcp.plot(df_xy, x='Voltage', y=['Voltage', 'I [A]'], twin_x=True, legend='Die',
         grid_major_y2=True, grid_major_y2_style='--', y2max=1.4,
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25 & Die=="(-1,2)"')

Multiple x & y values


fcp.plot(df_xy, x=['Boost Level', 'I [A]'], y=['Voltage', 'Temperature [C]'], legend='Die',
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')

Grouping

Row plot


fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', row='Boost Level', ax_size=[225, 225], legend_edge_color='#000000',
         filter='Substrate=="Si" & Target Wavelength==450 & Temperature [C]==25', label_row_fill_color='#000000', ax_edge_width=4,
         label_row_font_color='#ff0000', label_row_edge_color='#0000ff', label_row_edge_width=2, legend_edge_width=3)
Warning: The following kwargs are not supported:
    - label_row_font_color

Column plot


fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', col='Boost Level', ax_size=[225, 225], legend_edge_color='#000000', ax_edge_width=5,
         filter='Substrate=="Si" & Target Wavelength==450 & Temperature [C]==25', label_col_fill_color='#000000', label_col_font_color='#ff0000')
Warning: The following kwargs are not supported:
    - label_col_font_color

Row x column grid


fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', col='Boost Level', row='Temperature [C]',
         modebar_visible=True, modebar_fill_color='#000000', ax_edge_width=1, ymin=0,
         ax_size=[225, 225], filter='Substrate=="Si" & Target Wavelength==450', label_rc_font_size=13)

Wrap plot


fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', wrap=['Temperature [C]', 'Boost Level'],
         ax_size=[225, 225], filter='Substrate=="Si" & Target Wavelength==450', label_rc_font_size=13)

Horizontal & vertical lines


fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False, legend=True,
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
         ax_hlines=[(0, '#FF0000', '--', 3, 1, 'Open', '#555555', 0.25), 1.2],
         ax_vlines=[(0.6, '#0000ff', ':'), (1, '#00FF00')])

Curve fitting


fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False,
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
         fit=1, fit_eqn=True, fit_rsq=True, fit_range_x=[1.3, 2])

Stat Lines


fcp.plot(df_xy, x='Voltage', y=['Boost Level', 'I [A]'], legend=True, stat='median',
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')

Confidence intervals

To demonstrate this feature we will use a special dataset:


df_interval = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_interval.csv')
df_interval.head()

x y
0 -1.0 -10.715459
1 -1.0 -9.972410
2 -1.0 -30.740532
3 -1.0 -31.368963
4 -1.0 -29.058633

fcp.plot(df_interval, x='x', y='y', lines=False, conf_int=0.95)

Control limits


fcp.plot(df_interval, x='x', y='y', lines=False, ucl=50, lcl=-50, ucl_fill_color='#FF0000', legend=True)

Reference line


fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', legend='Die',
         filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
         ref_line=df_xy['Voltage'], ref_line_legend_text='y=x', xmin=0, ymin=0, xmax=1.6, ymax=1.6)

bar


fcp.bar(df_bar, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25', horizontal=True)

fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, legend='Measurement')

fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, stacked=True, legend='Measurement')

fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, col='Measurement', row='T [C]', ax_hlines=0, ax_size=[300, 300])

boxplot


fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], group_means=True)

df_box['Row'] = [int(f) for f in df_box.index / 4]
fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], mean_diamonds=True, conf_coeff=0.95, legend='Row')

fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], violin=True)

fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], col='Region', ax_size=[300, 300])

contour


fcp.contour(df_contour, x='X', y='Y', z='Value', filled=False, cbar=False)

fcp.contour(df_contour, x='X', y='Y', z='Value', filled=False, levels=40, contour_width=2,
            xmin=-4, xmax=5, ymin=-4, ymax=6, cbar=True,
            show_points=True, marker_size=26, marker_fill_color='#00FF00')
Warning: The following kwargs are not supported:
    - contour_width

fcp.contour(df_contour, x='X', y='Y', z='Value', row='Batch', col='Experiment', filled=True,
            cbar=False, xmin=-3, xmax=3, ymin=-3, ymax=3, ax_size=[250,250],
            label_rc_font_size=12, levels=40)

gantt

Better luck next time…

heatmap


fcp.heatmap(df_heatmap, x='Category', y='Player', z='Average')

hist


fcp.hist(df_hist, x='Value', horizontal=True, bins=20)

fcp.hist(df_hist, x='Value', legend='Region', kde=True, kde_width=2)
Warning: The following kwargs are not supported:
    - kde_width
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[48], line 1
----> 1 fcp.hist(df_hist, x='Value', legend='Region', kde=True, kde_width=2)

File ~/Code/fivecentplots/src/fivecentplots/fcp.py:502, in hist(df, **kwargs)
    409 def hist(df, **kwargs):
    410     """Histogram plot.
    411
    412     Args:
   (...)
    499             .. figure:: ../_static/images/example_hist2.png
    500     """
--> 502     return plotter(data.Histogram, **utl.dfkwarg(df, kwargs, data.Histogram))

File ~/Code/fivecentplots/src/fivecentplots/fcp.py:1686, in plotter(dobj, **kwargs)
   1683 kwargs['timer'].get(f'ifig={ifig} | ir={ir} | ic={ic} | add_hvlines')
   1685 # Plot the data
-> 1686 dd = globals()['plot_{}'.format(dd.name)](dd, layout, ir, ic, df_rc, kwargs)
   1687 kwargs['timer'].get(f'ifig={ifig} | ir={ir} | ic={ic} | plot')
   1689 # Add rc labels

File ~/Code/fivecentplots/src/fivecentplots/fcp.py:1416, in plot_hist(data, layout, ir, ic, df_rc, kwargs)
   1399 """
   1400 Plot data as histogram
   1401
   (...)
   1409
   1410 """
   1411 for iline, df, x, y, z, leg_name, twin, ngroups in data.get_plot_data(df_rc):
   1412     # if kwargs.get('groups', False):  # no use case for this
   1413     #     for nn, gg in df.groupby(utl.validate_list(kwargs['groups'])):
   1414     #         hist, data = layout.plot_hist(ir, ic, iline, gg, x, y, leg_name, data)
   1415     # else:
-> 1416     hist, data = layout.plot_hist(ir, ic, iline, df, x, y, leg_name, data)
   1418 return data

File ~/Code/fivecentplots/src/fivecentplots/engines/plotly.py:1602, in Layout.plot_hist(self, ir, ic, iline, df, x, y, leg_name, data)
   1600     y0 = np.linspace(data.ranges['ymin'][ir, ic], data.ranges['ymax'][ir, ic], 1000)
   1601     x0 = kde(y0)
-> 1602 kwargs = self.make_kw_dict(self.kde)
   1603 kwargs['color'] = RepeatedList(kwargs['color'][iline], 'color')
   1604 mls = dict(line=dict(width=self.kde.width[iline],
   1605                      color=self.kde.color[iline],
   1606                      dash=self.kde.style[iline],
   1607                      ))

File ~/Code/fivecentplots/src/fivecentplots/engines/layout.py:2776, in BaseLayout.make_kw_dict(self, element, pop)
   2774 kwargs['edge_color'] = copy.copy(element.edge_color)
   2775 kwargs['edge_width'] = copy.copy(element.edge_width)
-> 2776 kwargs['edge_width_adj'] = copy.copy(element.edge_width_adj)
   2777 kwargs['font'] = copy.copy(element.font)
   2778 kwargs['font_weight'] = copy.copy(element.font_weight)

AttributeError: 'Element' object has no attribute 'edge_width_adj'
[ ]:
fcp.hist(img_rgb, legend='Channel', markers=False, ax_size=[600, 400], line_width=2, colors=fcp.RGB)
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/plotly.py(2033)show()
   2031             # pio.renderers.default = 'iframe'  # not sure about this
   2032             db()
-> 2033             self.fig.obj.show(config=config)
   2034 
   2035     def update_markers(self):

imshow


fcp.imshow(img_rgb, ax_size=[600, 300])

img_raw = fcp.utilities.img_grayscale(img_rgb)
fcp.imshow(img_raw, ax_size=[600, 600], title='Fake RAW, Fake Pirate', cbar=True, title_edge_width=1, title_edge_color='#ff0000')

url = 'https://upload.wikimedia.org/wikipedia/commons/2/28/RGB_illumination.jpg'
img_rgb_sp = imageio.imread(url)
img_raw_sp = fcp.utilities.rgb2bayer(img_rgb_sp)
fcp.imshow(img_raw_sp, cmap='inferno', ax_size=[300, 300], cfa='rggb', wrap='Plane', ax_edge_width=1, ax_edge_color='#555555')

nq


fcp.nq(df_box, x='Value', marker_size=4, line_width=2)

img_rgb = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))
img_cat = fcp.utl.img_grayscale(img_rgb, bit_depth=12)
fcp.nq(img_cat, marker_size=4, line_width=2)

pie


df_pie = df_bar.copy()
df_pie.loc[df_pie.pH < 0, 'pH'] = -df_pie.pH
fcp.pie(df_pie, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25')

fcp.pie(df_pie, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25', explode=[0.1], legend=True)
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/plotly.py(2458)show()
   2456             # pio.renderers.default = 'iframe'  # not sure about this
   2457             db()
-> 2458             self.fig.obj.show(config=config)
   2459 
   2460     def update_markers(self):